'''
本程序用于实现学生信息管理系统

程序的实现功能：
添加学生及成绩信息；
将学生信息保存在文件中；
修改和删除学生信息；
查询学生信息；
根据学生成绩进行排序；
统计学生的总分

'''

import os

filename = 'students.txt'


def main():
    while True:  # 为了显示主菜单
        menu()  # 调用menu()函数
        #  有各种功能，下面就是让用户选择
        choice = int(input('请选择'))
        if choice in [0, 1, 2, 3, 4, 5, 6, 7]:  # 共有八个功能，判断选择的是否在这八个序号里面
            if choice == 0:  # 选择0，表示退出系统
                answer = input('您确定要退出系统吗?y/n\n')  # 输出一个询问，是否要退出
                if answer == 'y' or answer == 'Y':  # 判断输入的是否为y
                    print('谢谢您的使用')
                    break  # 打断menu()函数的输出
                else:  # 不是选的y
                    continue  # 继续程序执行
            elif choice == 1:  # 如果选择的是1
                insert()  # 调用insert()函数，录入学生信息
            elif choice == 2:  # 如果选择的是2
                search()  # 调用search()函数，查找学生信息
            elif choice == 3:  # 如果选择的是3
                delete()  # 调用delete()函数，删除学生信息
            elif choice == 4:  # 如果选择的是4
                modify()  # 调用modify()函数，修改学生信息
            elif choice == 5:  # 如果选择的是5
                sort()  # 调用sort()函数，对学生成绩进行排序
            elif choice == 6:  # 如果选择的是6
                total()  # 调用total()函数，统计学生总人数
            elif choice == 7:  # 如果选择的是7
                show()  # 调用show()函数，显示所有学生的信息


def menu():
    print('======================学生信息管理系统======================')
    print('-------------------------功能菜单-------------------------')
    print('\t\t\t\t\t\t1.录入学生信息')
    print('\t\t\t\t\t\t2.查找学生信息')
    print('\t\t\t\t\t\t3.删除学生信息')
    print('\t\t\t\t\t\t4.修改学生信息')
    print('\t\t\t\t\t\t5.排序')
    print('\t\t\t\t\t\t6.统计学生总人数')
    print('\t\t\t\t\t\t7.显示所有学生信息')
    print('\t\t\t\t\t\t0.退出系统')
    print('---------------------------------------------------------')


def insert():  # 定义insert()函数，录入学生信息
    student_list = []  # 创建一个列表，用于存储录入的学生信息
    while True:  # 循环录入学生信息
        id = input('请输入学号(如1001):')
        if not id:  # 如果没有输入学号或者输入错误，则执行break，退出录入信息操作
            break
        name = input('请输入姓名:')
        if not name:  # 如果是空的，则执行break
            break

        #  然后开始录入成绩信息，但是成绩有可能录入错误，因此用try...except...保证异常处理
        try:
            english = int(input('请输入英语成绩:'))
            python = int(input('请输入python成绩:'))
            java = int(input('请输入Java成绩:'))
        except:  # 当你输入的成绩无效时，会执行except语句
            print('输入无效，不是整数类型，请重新输入')
            continue
        # 将录入的学生信息保存到字典
        student = {'id': id, 'name': name, 'english': english, 'python': python, 'java': java}
        # 将学生信息添加到列表中
        student_list.append(student)
        anewer = input('是否继续添加?y/n\n')
        if anewer == 'y':
            continue
        else:
            break

    # 信息添加之后，将信息保存到文件中，需要退出循环
    # 调用save()函数，保存信息
    save(student_list)  # save()函数未定义，需要自行定义
    print('学生信息录入完毕!!!')


def save(lst):  # 传进去一个列表
    # 然后将列表中的内容保存在文件中
    try:
        stu_txt = open(filename, 'a', encoding='UTF-8')
    except:
        stu_txt = open(filename, 'w', encoding='UTF-8')
    for item in lst:
        stu_txt.write(str(item) + '\n')
    stu_txt.close()


def search():  # 定义search()函数，查找学生信息
    student_query = []
    while True:
        id = ''
        name = ''
        if os.path.exists(filename):
            # 现在分模式查找，1代表使用id查找，2代表使用name查找
            mode = input('按学号查找请输入1，按姓名查找请输入2')
            if mode == '1':  # 需要加上单引号，因为输入的是字符串，并未转变类型
                id = input('请输入要查找学生的id:')
            elif mode == '2':  # elif就相当于else if的功能，主要在有多个选择时使用,因为if先用来判断是否为1
                # 下面还有两个选择,就是2和其他的数，因此不能直接用else，还要用elif判断一下是否为2
                name = input('请输入要查找学生的姓名:')
            else:
                print('您的输入有误，请重新输入')
                search()  # 输入错了，就重新调用函数，也可以使用continue
            with open(filename, 'r', encoding='UTF-8') as rfile:  # 读取内容，将所有内容放在student文件中
                student = rfile.readlines()
                for item in student:  # 遍历student列表
                    d = dict(eval(item))  # 字符串转成字典类型
                    if id != '':
                        if d['id'] == id:
                            student_query.append(d)
                    if name != '':
                        if d['name'] == name:
                            student_query.append(d)
            # 显示查询结果
            show_student(student_query)  # 定义show_student函数
            # 清空列表
            student_query.clear()
            answer = input('是否继续执行查询操作?y/n\n')
            if answer == 'y':
                continue
            else:
                break
        else:
            print('未录入学生信息')
            return


def show_student(lst):
    # 显示查询结果的过程，结果是按照一定的格式显示的，因此要使用格式化字符串
    if len(lst) == 0:
        print('没有查询到学生信息，无数据显示!!!')
        return
    #  如果查到了，就要定义标题的显示格式
    format_title = '{:^6}\t{:^12}\t{:^8}\t{:^10}\t{:^10}\t{:^8}'
    print(format_title.format('id', '姓名', '英语成绩', 'python成绩', 'java成绩', '总成绩'))
    # 定义内容的显示格式
    format_data = '{:^6}\t{:^12}\t{:^8}\t{:^10}\t{:^10}\t{:^8}'
    for item in lst:
        print(format_data.format(item.get('id'),
                                 item.get('name'),
                                 item.get('english'),
                                 item.get('python'),
                                 item.get('java'),
                                 int(item.get('english')) + int(item.get('python')) + int(item.get('java'))
                                 ))


def delete():  # 定义delete()函数，删除学生信息
    while True:
        student_id = input('请输入要删除的学生的id:')
        if student_id != '':
            # 当输入的id之后，则不是空的，此时要判断导入id是否在文件中，使用os模块
            if os.path.exists(filename):  # 判断文件是否存在
                with open(filename, 'r', encoding='UTF-8') as file:
                    student_old = file.readlines()  # 如果存在，读取学生的信息，将其添加到列表当中
            else:  # 如果不存在
                student_old = []  # 建立一个空列表
            flag = False  # 标记是否删除
            if student_old:  # 这里表示如果列表student_old为真，则执行下面with语句
                with open(filename, 'w', encoding='UTF-8') as wfile:  # 使用上下管理器，写入
                    d = {}  # 创建一个空字典
                    for item in student_old:  # 遍历student_old中的信息
                        d = dict(eval(item))  # 将字符串转成字典
                        if d['id'] != student_id:  # 判断是否与输入的信息相等
                            wfile.write(str(d) + '\n')  # 不相等，则写入d字典中
                        else:
                            flag = True  # 相等则执行删除操作
                    if flag == 1:
                        print(f'id为{student_id}的学生信息已被删除')
                    else:
                        print(f'没有找到id为{student_id}的学生信息')
            else:  # 文件不存在
                print('无学生信息')
                break
            show()  # 删除之后重新显示全部学生信息
            answer = input('是否继续删除学生信息?y/n\n')
            if answer == 'y':
                continue
            else:
                break


def modify():  # 定义modify()函数，修改学生信息
    show()
    if os.path.exists(filename):
        with open(filename, 'r', encoding='UTF-8') as rfile:
            student_old = rfile.readlines()  # readlines() 函数用于读取文件中的所有行，然后将起放入创建的列表中
    else:
        return  # 文件不存在，结束函数
    student_id = input('请输入需要修改学生的id:')
    if student_id != '':
        if os.path.exists(filename):
            with open(filename, 'w', encoding='UTF-8') as wfile:
                for item in student_old:
                    d = dict(eval(item))
                    if d['id'] == student_id:
                        print('找到学生相关信息，可以修改他的相关信息了!!!')
                        while True:
                            try:
                                d['name'] = input('请输入名字:')
                                d['english'] = input('请输入英语成绩:')
                                d['python'] = input('请输入python成绩:')
                                d['java'] = input('请输入java成绩')
                            except:
                                print('输入有误，请重新输入')  # 如果输入有误，则会继续执行while true
                            else:
                                break
                        # 如果都没输入错误，则使用write写入
                        wfile.write(str(d) + '\n')
                        print('修改成功')
                    # 一些学生被修改，还有一些未修改的学生，也就是id不相等的
                    else:
                        wfile.write(str(d) + '\n')
                answer = input('是否继续修改其他学生的信息?y/n\n')
                if answer == 'y':
                    modify()  # 在函数里面调用函数


def sort():  # 定义sort()函数，对学生成绩进行排序
    show()
    if os.path.exists(filename):
        with open(filename, 'r', encoding='UTF-8') as rfile:
            student_list = rfile.readlines()
        student_new = []
        for item in student_list:
            d = dict(eval(item))
            student_new.append(d)
    else:
        return
    # 共有升序和降序两种排序方式，手动输入
    asc_or_desc = input('请选择(0.升序 1.降序)')
    if asc_or_desc == '0':
        asc_or_desc_bool = False
    elif asc_or_desc == '1':
        asc_or_desc_bool = True
    else:
        print('您的输入有误，请重新输入')
        sort()
    mode = input('请选择排序方式(1.英语成绩排序 2.python成绩排序 3.java成绩排序 0.总成绩排序)')
    if mode == '1':
        student_new.sort(key=lambda x: int(x['english']), reverse=asc_or_desc_bool)
    elif mode == '2':
        student_new.sort(key=lambda x: int(x['python']), reverse=asc_or_desc_bool)
    elif mode == '3':
        student_new.sort(key=lambda x: int(x['java']), reverse=asc_or_desc_bool)
    elif mode == '0':
        student_new.sort(key=lambda x: int(x['english']) + int(x['python']) + int(x['java']), reverse=asc_or_desc_bool)
    else:
        print('您的输入有误，请重新输入')
        sort()
    show_student(student_new)


def total():  # 定义total()函数，统计学生总人数
    if os.path.exists(filename):
        with open(filename, 'r', encoding='UTF-8') as rfile:
            students = rfile.readlines()
            if students:
                print(fr'一共有{len(students)}名学生')
            else:
                print('尚未录入学生信息')


def show():  # 定义show()函数，显示所有学生的信息
    student_lst = []
    if os.path.exists(filename):
        with open(filename, 'r', encoding='UTF-8') as rfile:
            students = rfile.readlines()
            for item in students:
                student_lst.append(eval(item))
            if student_lst:
                show_student(student_lst)
    else:
        print('尚未录入学生信息!!!')


if __name__ == '__main__':
    main()